#include <mips/regdef.h>
#include <sys/syscall.h>

	.data
	.align 2

mensaje_error_0: 
	.asciiz "\nEl archivo finaliza incorrectamente\n"
mensaje_error_1: 
	.asciiz "\nEl caracter leido no es un valor binario\n"
espacio_lectura: 
	.byte 0,0,0,0,0,0,0,0
espacio_escritura: 
	.byte 0
conversion_ascii: 
	.byte 128,64,32,16,8,4,2,1
char_cero: 
	.ascii "0" 
char_uno: 
	.ascii "1" 

// ----------------------------------------------------------------------------------

	.text
	.align 2

	.global decode
	.ent decode

decode:
	.frame 	$fp,32,ra
	.set noreorder
	.cpload t9
	.set reorder

	subu 	sp,sp,32 				#creo el stack frame correspondiente
	.cprestore 16

	sw 	ra,24(sp) 				#almaceno los valores correspondientes al registro fp, gp y ra
	sw 	$fp,20(sp) 			
	sw 	gp,16(sp) 			
	move 	$fp,sp
	sw 	a0,32($fp) 				#guardo el argumento enviado por la funcion main en el stack de la caller

	li 	t0, 0 					#inicializo t0 en 0, utilizado como contador para el loop
	move 	t1, zero 				#t1 es el char que vamos decodificar
	move 	t4, a0 					#paso la direccion del espacio a t4
	la 	t2, conversion_ascii

decode_for:
	li 	t3,8
	beq 	t0,t3,decode_endloop 	#condición para terminar el ciclo
	lbu 	t5,0(t4) 				#Leo un char del buffer
	addi 	t4,t4,1 				#sumo el offset
	lbu 	t6, char_cero(zero) 	#Leo un ascii "0" para usarlo en la comparacion
	beq 	t5,t6,decode_is_zero
	lbu 	t6, char_uno(zero) 		#Leo un ascii "1" para usarlo en la comparación
	bne 	t5,t6,decode_end 

	lbu 	t3, 0(t2) 				#leo el vector utilizado para conversion de ascii
	addi 	t2,t2,1 				#sumo el offset al vector de mascaras
	or 	t1,t1,t3 				#Pongo en 1 el bit correspondiente
	addi 	t0, t0, 1 				#Aumento en 1 el contador
	b 	decode_for 				#vuelvo al comienzo del for

decode_is_zero:
	addi 	t0, t0, 1 				#Aumento en 1 el contador
	addi 	t2,t2,1 				#sumo el offset al vector de mascaras
	b 	decode_for 				#Loopea una vez mas

decode_endloop:
	li 	a0, 1 					#Guardo 1 porque quiero escribir al stdout
	sb 	t1,espacio_escritura(zero) 		#Guardo el char a escribir en el buffer
	la 	a1, espacio_escritura	#Le paso el bufer
	li 	a2, 1 					#Guardo 1 porque quiero escribir solo un byte
	
	li 	v0,SYS_write 			#carga en v0 el codigo correspondiente a la escritura
	syscall
	
	bne 	a3,zero,decode_end  				
	
	li 	v0,0 					#caso contrario la escritura fue correcta
	b 	decode_end

decode_end:
	lw 	ra,24($fp) 				#Recupero los registros fp, gp y ra del stack
	lw 	$fp,20($fp) 			
	lw 	gp,16($fp) 				
	addu 	sp,sp,32
	j 		ra						#vuelvo al main

	.end decode

// ----------------------------------------------------------------------------------

	.global main
	.ent main

main:
	.frame $fp,32,ra
	.set noreorder
	.cpload t9
	.set reorder

	subu 	sp,sp,32 				#creo el stack frame correspondiente
	.cprestore 16

	sw 		ra,24(sp) 				#almaceno los valores correspondientes al registro fp, gp y ra
	sw 		$fp,20(sp) 				
	sw 		gp,16(sp) 				
	move 	$fp,sp
	
	sw 		a0,32($fp) 				
	sw 		a0,36($fp) 				

	move 	v0, zero 				#Inicializa v0 con cero

main_while:
	li 		a0, 0 					#lectura por stdin
	la 		a1, espacio_lectura 	#espacio destinado para la lectura
	li 		a2, 8 					#Guardo 8 (quiero levantar 8 '0's y '1's)
	li 		v0,SYS_read
	syscall
	
	bne 	a3,zero,main_error	
	
	li 		t0, 8
	bne 	t0,v0,main_error2 		#Si no leyo 8 caracteres, analizo si es eof o archivo mal formado

	la 		t0,espacio_lectura(zero) 	#Cargo el espacio leido
	move 	a0, t0 					#Preparo el espacio leido como parámetro de encode
	jal 	decode
	bnez 	v0,main_error3 			#Sale del programa si hay error
	b 		main_while 				#Loopea hasta que no haya nada mas que leer

main_error:
	li 		v0, 2 					#Muevo el codigo de error al retorno de la funcion y salgo de esta
	b 		main_end

main_error2:
	beqz 	v0,main_end 			#Leyo 0 caracteres, es eof
	li 		v0, 3 					#Muevo el codigo de error al retorno de la funcion y salgo de esta
	li 		a0, 1 					
	la 		a1, mensaje_error_0 	#Paso el espacio de lectura
	li 		a2, 59
	li 		v0,SYS_write
	syscall
	b 		main_end

main_error3:
	li 		a0, 1 					
	la 		a1, mensaje_error_1		#Paso el espacio de lectura
	li 		a2, 49
	li 		v0,SYS_write
	syscall
	b 		main_end

main_end:
	lw 		ra,24(sp) 				#Recupero los registros fp, gp y ra del stack
	lw 		$fp,20(sp) 
	lw 		gp,16(sp) 
	addu 	sp,sp,32
	j 		ra						#vuelvo el control al llamante
	
	.end main
